D:\a\tools.proto\tools.proto\compiler\src\gen\base\structure.rs
Line | Count | Source |
1 | | // Copyright (c) 2024, BlockProject 3D |
2 | | // |
3 | | // All rights reserved. |
4 | | // |
5 | | // Redistribution and use in source and binary forms, with or without modification, |
6 | | // are permitted provided that the following conditions are met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright notice, |
9 | | // this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above copyright notice, |
11 | | // this list of conditions and the following disclaimer in the documentation |
12 | | // and/or other materials provided with the distribution. |
13 | | // * Neither the name of BlockProject 3D nor the names of its contributors |
14 | | // may be used to endorse or promote products derived from this software |
15 | | // without specific prior written permission. |
16 | | // |
17 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
18 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
19 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
21 | | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
22 | | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
23 | | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
24 | | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
25 | | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
26 | | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | |
29 | | use crate::compiler::structure::{Field, FieldRaw, FieldType, FieldView, FixedField, FixedFieldType, Structure}; |
30 | | use crate::compiler::util::types::TypeMapper; |
31 | | use crate::gen::base::map::TypePathMapper; |
32 | | use crate::gen::template::hook::{Render, TemplateHooks}; |
33 | | use crate::gen::template::{Scope, Template}; |
34 | | use crate::model::protocol::{Description, Endianness}; |
35 | | use itertools::Itertools; |
36 | | use std::borrow::Cow; |
37 | | |
38 | | pub trait Utilities { |
39 | | fn get_field_type(field_type: FixedFieldType) -> &'static str; |
40 | | fn get_fragment_name(field: &Field) -> &'static str; |
41 | | fn get_bit_codec_inline(endianness: Endianness) -> &'static str; |
42 | | fn get_byte_codec_inline(endianness: Endianness) -> &'static str; |
43 | | fn get_byte_codec(endianness: Endianness) -> &'static str; |
44 | 0 | fn gen_description(desc: &Description) -> Cow<str> { |
45 | 0 | match desc { |
46 | 0 | Description::Single(v) => Cow::Borrowed(v), |
47 | 0 | Description::Multi(v) => Cow::Owned(v.join(" ")), |
48 | | } |
49 | 0 | } |
50 | | } |
51 | | |
52 | | enum Mode { |
53 | | Getter, |
54 | | Setter, |
55 | | } |
56 | | |
57 | | impl Mode { |
58 | 800 | pub fn get_path<'a>(&self, getter: &'a str, setter: &'a str) -> &'a str { |
59 | 800 | match self { |
60 | 400 | Mode::Getter => getter, |
61 | 400 | Mode::Setter => setter, |
62 | | } |
63 | 800 | } |
64 | | } |
65 | | |
66 | 708 | fn gen_structure_field_prologue<'a, 'fragment, 'variable: 'fragment, U: Utilities>( |
67 | 708 | template: &'variable Template<'fragment, 'variable>, |
68 | 708 | field: &'variable Field, |
69 | 708 | ) -> Scope<'a, 'fragment, 'variable> { |
70 | 708 | let mut scope = template.scope(); |
71 | 708 | scope |
72 | 708 | .var_d("start", field.loc.byte_offset) |
73 | 708 | .var_d("end", field.loc.byte_offset + field.loc.byte_size) |
74 | 708 | .var("name", &field.name) |
75 | 708 | .var( |
76 | 708 | "description", |
77 | 708 | field.description.as_ref().map(U::gen_description).unwrap_or("".into()), |
78 | 708 | ) |
79 | 708 | .var_d("info", field); |
80 | 708 | scope |
81 | 708 | } |
82 | | |
83 | 472 | fn gen_structure_field<U: Utilities, G: FnMut(Mode, &Field, &FixedField, Scope) -> String>( |
84 | 472 | mode: Mode, |
85 | 472 | field: &Field, |
86 | 472 | template: &Template, |
87 | 472 | field_generator: &mut G, |
88 | 472 | ) -> Option<String> { |
89 | 472 | let mut scope = gen_structure_field_prologue::<U>(template, field); |
90 | 472 | match &field.ty { |
91 | 400 | FieldType::Fixed(v) => { |
92 | 400 | let bits_type = U::get_field_type(v.bits_type); |
93 | 400 | let raw_type = U::get_field_type(v.raw_type); |
94 | 400 | scope |
95 | 400 | .var("bits_type", bits_type) |
96 | 400 | .var("raw_type", raw_type) |
97 | 400 | .var_d("bit_offset", field.loc.bit_offset) |
98 | 400 | .var_d("bit_size", field.loc.bit_size); |
99 | 400 | Some(field_generator(mode, field, v, scope)) |
100 | | } |
101 | 72 | _ => None, |
102 | | } |
103 | 472 | } |
104 | | |
105 | 120 | fn gen_structure<'variable, U: Utilities, G: FnMut(Mode, &Field, &FixedField, Scope) -> String>( |
106 | 120 | s: &'variable Structure, |
107 | 120 | mut template: Template<'_, 'variable>, |
108 | 120 | mut field_generator: G, |
109 | 120 | ) -> String { |
110 | 120 | template.var("struct_name", &s.name).var( |
111 | 120 | "struct_description", |
112 | 120 | s.description.as_ref().map(U::gen_description).unwrap_or("".into()), |
113 | 120 | ); |
114 | 120 | let getters = s |
115 | 120 | .fields |
116 | 120 | .iter() |
117 | 236 | .filter_map(|v| gen_structure_field::<U, G>(Mode::Getter, v, &template, &mut field_generator)) |
118 | 120 | .join(""); |
119 | 120 | let setters = s |
120 | 120 | .fields |
121 | 120 | .iter() |
122 | 236 | .filter_map(|v| gen_structure_field::<U, G>(Mode::Setter, v, &template, &mut field_generator)) |
123 | 120 | .join(""); |
124 | 120 | let mut code = template.render("", &["decl"]).unwrap(); |
125 | 120 | if !getters.is_empty() { Branch (125:8): [True: 54, False: 6]
Branch (125:8): [True: 54, False: 6]
Branch (125:8): [True: 0, False: 0]
Branch (125:8): [True: 0, False: 0]
Branch (125:8): [Folded - Ignored]
|
126 | 108 | code += &template.var("fields", getters).render("", &["getters"]).unwrap(); |
127 | 108 | }12 |
128 | 120 | if !setters.is_empty() { Branch (128:8): [True: 54, False: 6]
Branch (128:8): [True: 54, False: 6]
Branch (128:8): [True: 0, False: 0]
Branch (128:8): [True: 0, False: 0]
Branch (128:8): [Folded - Ignored]
|
129 | 108 | code += &template.var("fields", setters).render("", &["setters"]).unwrap(); |
130 | 108 | }12 |
131 | 120 | code |
132 | 120 | } |
133 | | |
134 | 200 | fn gen_field_raw<'variable>( |
135 | 200 | mode: Mode, |
136 | 200 | _: &'variable Field, |
137 | 200 | fixed: &'variable FixedField, |
138 | 200 | mut scope: Scope<'_, '_, 'variable>, |
139 | 200 | ) -> String { |
140 | 200 | let path = mode.get_path("getters.field", "setters.field"); |
141 | 200 | match &fixed.raw { |
142 | | FieldRaw::Transmute => { |
143 | 72 | if fixed.raw_type == FixedFieldType::Bool { Branch (143:16): [True: 24, False: 48]
Branch (143:16): [Folded - Ignored]
|
144 | 24 | scope.render_to_var(path, &["transmute_bool"], "fragment").unwrap() |
145 | | } else { |
146 | 48 | scope.render_to_var(path, &["transmute_other"], "fragment").unwrap() |
147 | | } |
148 | | } |
149 | 20 | FieldRaw::SignedCast(max_positive) => { |
150 | 20 | scope.var_d("max_positive", max_positive).render_to_var(path, &["signed"], "fragment").unwrap() |
151 | | } |
152 | 108 | FieldRaw::None => scope.render_to_var(path, &["none"], "fragment").unwrap(), |
153 | | }; |
154 | 200 | scope.render(mode.get_path("getters", "setters"), &["field"]).unwrap() |
155 | 200 | } |
156 | | |
157 | 200 | fn gen_field_bin<'variable, U: Utilities>( |
158 | 200 | mode: Mode, |
159 | 200 | field: &'variable Field, |
160 | 200 | fixed: &'variable FixedField, |
161 | 200 | mut scope: Scope<'_, '_, 'variable>, |
162 | 200 | ) -> String { |
163 | 200 | let fragment_name = U::get_fragment_name(field); |
164 | 200 | if field.loc.bit_size % 8 != 0 { Branch (164:8): [True: 64, False: 136]
Branch (164:8): [True: 0, False: 0]
Branch (164:8): [Folded - Ignored]
|
165 | 64 | let path = mode.get_path("getters.field.bit", "setters.field.bit"); |
166 | 64 | scope |
167 | 64 | .var("codec", U::get_bit_codec_inline(fixed.endianness)) |
168 | 64 | .render_to_var(path, &[fragment_name], "fragment") |
169 | 64 | .unwrap(); |
170 | 136 | } else { |
171 | 136 | let path = mode.get_path("getters.field.byte", "setters.field.byte"); |
172 | 136 | scope |
173 | 136 | .var("codec", U::get_byte_codec_inline(fixed.endianness)) |
174 | 136 | .render_to_var(path, &[fragment_name], "fragment") |
175 | 136 | .unwrap(); |
176 | 136 | } |
177 | 200 | scope.render(mode.get_path("getters", "setters"), &["field"]).unwrap() |
178 | 200 | } |
179 | | |
180 | 118 | fn gen_field_getter<U: Utilities, T: TypeMapper>( |
181 | 118 | field: &Field, |
182 | 118 | template: &Template, |
183 | 118 | type_path_map: &TypePathMapper<T>, |
184 | 118 | ) -> String { |
185 | 118 | let mut scope = gen_structure_field_prologue::<U>(template, field); |
186 | 118 | match &field.ty { |
187 | 100 | FieldType::Fixed(v) => gen_field_view_getter::<U, T>(v, &scope, type_path_map), |
188 | 6 | FieldType::Array(v) => scope |
189 | 6 | .var("raw_type", U::get_field_type(v.ty)) |
190 | 6 | .var("codec", U::get_byte_codec(v.endianness)) |
191 | 6 | .var_d("bit_size", v.item_bit_size) |
192 | 6 | .render("getters", &["array"]) |
193 | 6 | .unwrap(), |
194 | 12 | FieldType::Struct(v) => scope.var("type_name", type_path_map.get(v)).render("getters", &["struct"]).unwrap(), |
195 | | } |
196 | 118 | } |
197 | | |
198 | 118 | fn gen_field_setter<U: Utilities, T: TypeMapper>( |
199 | 118 | field: &Field, |
200 | 118 | template: &Template, |
201 | 118 | type_path_map: &TypePathMapper<T>, |
202 | 118 | ) -> String { |
203 | 118 | let mut scope = gen_structure_field_prologue::<U>(template, field); |
204 | 118 | match &field.ty { |
205 | 100 | FieldType::Fixed(v) => gen_field_view_setter::<U, T>(v, &scope, type_path_map), |
206 | 6 | FieldType::Array(v) => scope |
207 | 6 | .var("raw_type", U::get_field_type(v.ty)) |
208 | 6 | .var("codec", U::get_byte_codec(v.endianness)) |
209 | 6 | .var_d("bit_size", v.item_bit_size) |
210 | 6 | .render("setters", &["array"]) |
211 | 6 | .unwrap(), |
212 | 12 | FieldType::Struct(v) => scope.var("type_name", type_path_map.get(v)).render("setters", &["struct"]).unwrap(), |
213 | | } |
214 | 118 | } |
215 | | |
216 | 100 | fn gen_field_view_getter<U: Utilities, T: TypeMapper>( |
217 | 100 | field: &FixedField, |
218 | 100 | scope: &Scope, |
219 | 100 | type_path_map: &TypePathMapper<T>, |
220 | 100 | ) -> String { |
221 | 100 | let mut scope = scope.clone(); |
222 | 100 | scope.var("raw_type", U::get_field_type(field.raw_type)); |
223 | 100 | match &field.view { |
224 | 4 | FieldView::Float { a, b, .. } => scope |
225 | 4 | .var("view_type", U::get_field_type(field.view_type)) |
226 | 4 | .var("a", format!("{:?}", a)) |
227 | 4 | .var("b", format!("{:?}", b)) |
228 | 4 | .render("getters", &["view_float"]) |
229 | 4 | .unwrap(), |
230 | 6 | FieldView::Enum(r) => scope |
231 | 6 | .var("view_type", type_path_map.get(r)) |
232 | 6 | .var("repr_type", U::get_field_type(r.repr_type)) |
233 | 6 | .render("getters", &["view_enum"]) |
234 | 6 | .unwrap(), |
235 | 90 | FieldView::None => scope |
236 | 90 | .var("view_type", U::get_field_type(field.view_type)) |
237 | 90 | .render("getters", &["view_none"]) |
238 | 90 | .unwrap(), |
239 | | } |
240 | 100 | } |
241 | | |
242 | 100 | fn gen_field_view_setter<U: Utilities, T: TypeMapper>( |
243 | 100 | field: &FixedField, |
244 | 100 | scope: &Scope, |
245 | 100 | type_path_map: &TypePathMapper<T>, |
246 | 100 | ) -> String { |
247 | 100 | let mut scope = scope.clone(); |
248 | 100 | scope.var("raw_type", U::get_field_type(field.raw_type)); |
249 | 100 | match &field.view { |
250 | 4 | FieldView::Float { a_inv, b_inv, .. } => scope |
251 | 4 | .var("view_type", U::get_field_type(field.view_type)) |
252 | 4 | .var("a_inv", format!("{:?}", a_inv)) |
253 | 4 | .var("b_inv", format!("{:?}", b_inv)) |
254 | 4 | .render("setters", &["view_float"]) |
255 | 4 | .unwrap(), |
256 | 6 | FieldView::Enum(r) => scope |
257 | 6 | .var("view_type", type_path_map.get(r)) |
258 | 6 | .var("repr_type", U::get_field_type(r.repr_type)) |
259 | 6 | .render("setters", &["view_enum"]) |
260 | 6 | .unwrap(), |
261 | 90 | FieldView::None => scope |
262 | 90 | .var("view_type", U::get_field_type(field.view_type)) |
263 | 90 | .render("setters", &["view_none"]) |
264 | 90 | .unwrap(), |
265 | | } |
266 | 100 | } |
267 | | |
268 | 60 | fn gen_structure_getters<U: Utilities, T: TypeMapper>( |
269 | 60 | s: &Structure, |
270 | 60 | template: &Template, |
271 | 60 | type_path_map: &TypePathMapper<T>, |
272 | 60 | ) -> String { |
273 | 60 | let mut scope = template.scope(); |
274 | 118 | let fields = s.fields.iter().map(|v| gen_field_getter::<U, T>(v, template, type_path_map)).join(""); |
275 | 60 | scope.var("fields", fields).render("", &["getters"]).unwrap() |
276 | 60 | } |
277 | | |
278 | 60 | fn gen_structure_setters<U: Utilities, T: TypeMapper>( |
279 | 60 | s: &Structure, |
280 | 60 | template: &Template, |
281 | 60 | type_path_map: &TypePathMapper<T>, |
282 | 60 | ) -> String { |
283 | 60 | let mut scope = template.scope(); |
284 | 118 | let fields = s.fields.iter().map(|v| gen_field_setter::<U, T>(v, template, type_path_map)).join(""); |
285 | 60 | scope.var("fields", fields).render("", &["setters"]).unwrap() |
286 | 60 | } |
287 | | |
288 | | pub struct Templates<'fragment, 'variable> { |
289 | | pub field_template: Template<'fragment, 'variable>, |
290 | | pub template: Template<'fragment, 'variable>, |
291 | | pub bits_template: Template<'fragment, 'variable>, |
292 | | pub raw_template: Template<'fragment, 'variable>, |
293 | | } |
294 | | |
295 | 60 | pub fn generate<'variable, U: Utilities, T: TypeMapper>( |
296 | 60 | templates: Templates<'_, 'variable>, |
297 | 60 | s: &'variable Structure, |
298 | 60 | type_path_map: &TypePathMapper<T>, |
299 | 60 | hooks: &TemplateHooks, |
300 | 60 | ) -> String { |
301 | 60 | let mut template = templates.template; |
302 | 60 | let mut field_template = templates.field_template; |
303 | 60 | field_template.var("struct_name", &s.name).var( |
304 | 60 | "struct_description", |
305 | 60 | s.description.as_ref().map(U::gen_description).unwrap_or("".into()), |
306 | 60 | ); |
307 | 60 | template.var("name", &s.name).var_d("byte_size", s.byte_size).var( |
308 | 60 | "struct_description", |
309 | 60 | s.description.as_ref().map(U::gen_description).unwrap_or("".into()), |
310 | 60 | ); |
311 | 60 | let mut code = template.render("", &["decl", "new", "fixed_size", "write_to", "from_bytes"]).unwrap(); |
312 | 60 | for frag26 in hooks.get_fragments("ext") { |
313 | 26 | code += &template.render_frag(frag).unwrap(); |
314 | 26 | } |
315 | 60 | code += &gen_structure_getters::<U, T>(s, &field_template, type_path_map); |
316 | 60 | code += &gen_structure_setters::<U, T>(s, &field_template, type_path_map); |
317 | 200 | code += &gen_structure::<U, _>(s, templates.bits_template, |mode, field, fixed, scope| { |
318 | 200 | gen_field_bin::<U>(mode, field, fixed, scope) |
319 | 200 | }); |
320 | 200 | code += &gen_structure::<U, _>(s, templates.raw_template, |mode, field, fixed, scope| { |
321 | 200 | gen_field_raw(mode, field, fixed, scope) |
322 | 200 | }); |
323 | 60 | code |
324 | 60 | } |